package top.dimples.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.dimples.common.ApiResponse;
import top.dimples.common.Status;
import top.dimples.config.LuckConfigProperties;
import top.dimples.mapper.UserProfileMapper;
import top.dimples.model.Role;
import top.dimples.model.UserProfile;
import top.dimples.model.UserRole;
import top.dimples.service.EmailManagerService;
import top.dimples.service.RoleService;
import top.dimples.service.UserProfileService;
import top.dimples.service.UserRoleService;
import top.dimples.utils.JwtUtil;
import top.dimples.vo.user.UserPasswordChangeVO;
import top.dimples.vo.user.UserProfileVO;
import top.dimples.vo.user.UserRegisterVO;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class UserProfileServiceImpl extends ServiceImpl<UserProfileMapper, UserProfile> implements UserProfileService {

    @Autowired
    private LuckConfigProperties luckConfigProperties;

    /**
     * 用户角色
     */
    @Autowired
    private UserRoleService userRoleService;


    @Autowired
    private EmailManagerService emailManagerService;


    @Autowired
    private RoleService roleService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    /**
     * 用户注册
     *
     * @param userRegisterVO 用户注册VO
     * @return 注册状态
     */
    @Override
    public ApiResponse userRegister(UserRegisterVO userRegisterVO) {
        // 1、 验证用户的用户名和邮箱，不能重复
        LambdaQueryWrapper<UserProfile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserProfile::getUsername, userRegisterVO.getUsername())
                .or()
                .eq(UserProfile::getEmail, userRegisterVO.getEmail());

        UserProfile user = this.getOne(wrapper);
        if (ObjectUtil.isNotEmpty(user)) {
            return ApiResponse.of(Status.BAD_REQUEST.getCode(), "用户已经存在", null);
        }

        // 2、用户注册，判断用户是否提交了昵称，没有提交昵称就将用户名设置为昵称
        if (StrUtil.isEmpty(userRegisterVO.getNickName())) {
            userRegisterVO.setNickName(userRegisterVO.getUsername());
        }
        UserProfile userProfile = UserProfile.builder()
                .username(userRegisterVO.getUsername())
                .password(SecureUtil.md5(userRegisterVO.getPassword()))
                .nickName(userRegisterVO.getNickName())
                .email(userRegisterVO.getEmail())
                .build();

        boolean userSaved = this.save(userProfile);

        // 3、注册完毕，发送邮件到用户到邮箱
        if (userSaved) {
            emailManagerService.sendRegisterEmail(userProfile);
            // 默认给用户添加普通用户的角色
            UserRole userRole = UserRole.builder()
                    .userId(userProfile.getId())
                    .roleId("1468224439932977153")
                    .build();
            return userRoleService.save(userRole) ? ApiResponse.ofSuccess() : ApiResponse.ofStatus(Status.ERROR);
        }
        return ApiResponse.ofStatus(Status.ERROR);
    }

    /**
     * 使用用户的ID获取用户信息
     *
     * @param id 用户的ID
     * @return 用户信息的响应实体
     */
    @Override
    public ApiResponse getUserInfoById(String id) {
        UserProfile userProfile = this.getById(id);
        UserProfileVO userProfileVO = new UserProfileVO();
        BeanUtil.copyProperties(userProfile, userProfileVO);
        return ObjectUtil.isNotEmpty(userProfile) ? ApiResponse.ofSuccess(userProfileVO) : ApiResponse.ofStatus(Status.BAD_REQUEST, "用户信息不存在");
    }

    /**
     * 修改用户的密码
     *
     * @param uId                  用户的ID
     * @param userPasswordChangeVO 用户修改密码的VO
     * @return 修改密码的响应
     */
    @Override
    public ApiResponse changeUserPassword(String uId, UserPasswordChangeVO userPasswordChangeVO) {
        // 1、检查密码的正确性
        UserProfile userProfile = this.getById(uId);
        if (!userProfile.getPassword().equals(SecureUtil.md5(userPasswordChangeVO.getOPassword()))) {
            return ApiResponse.of(Status.BAD_REQUEST.getCode(), "原密码错误", null);
        }
        // 2、修改密码
        userProfile.setPassword(SecureUtil.md5(userPasswordChangeVO.getNPassword()));
        return this.updateById(userProfile) ? ApiResponse.ofSuccess() : ApiResponse.ofStatus(Status.ERROR);
    }

    @Override
    public ApiResponse login(UserProfile userProfile) {
        return this.handleLogin(userProfile);
    }

    /**
     * 找回密码：发送邮件
     *
     * @param email 邮箱地址
     * @return 发送是否成功
     */
    @Override
    public ApiResponse forgetPassword(String email) {
        // 1、检查该邮箱是否存在
        UserProfile userProfile = this.getOne(new LambdaQueryWrapper<UserProfile>().eq(UserProfile::getEmail, email));
        if (ObjectUtil.isNotEmpty(userProfile)) {
            // 2、生成 key：用户id，并存入 redis，10分钟过期
            String key = UUID.fastUUID().toString();
            redisTemplate.opsForValue().set(key, userProfile.getId());
            // 3、拼接前端地址+key,发送邮件
            String forgetUrl = StrUtil.format("{}?key={}", luckConfigProperties.getForgetLocation(), key);
            emailManagerService.sendFindPasswordEmail(email, forgetUrl);
            return ApiResponse.ofSuccess();
        }
        return ApiResponse.of(Status.ERROR.getCode(), "用户不存在", null);
    }

    /**
     * 找回密码：修改密码
     *
     * @param key      邮件的 key
     * @param password 新密码
     * @return 修改的状态
     */
    @Override
    public ApiResponse changeFindPassword(String key, String password) {
        // 1、验证 key，取出用户 id，验证之后删除 key，
        String userId = redisTemplate.opsForValue().get(key);
        redisTemplate.delete(key);
        if (StrUtil.isNotEmpty(userId)) {
            // 2、取出用户修改密码
            UserProfile userProfile = this.getById(userId);
            userProfile.setPassword(SecureUtil.md5(password));
            return this.updateById(userProfile)
                    ? ApiResponse.ofSuccess()
                    : ApiResponse.of(Status.ERROR.getCode(), "修改失败", null);
        }
        return ApiResponse.of(Status.BAD_REQUEST.getCode(), "key不存在", null);
    }

    /**
     * 执行登陆
     *
     * @param userProfile 用户信息
     * @return
     */
    private ApiResponse handleLogin(UserProfile userProfile) {
        if (ObjectUtil.isNotEmpty(userProfile)) {
            HashMap<String, String> tokenMap = new HashMap<>();
            tokenMap.put("uId", userProfile.getId());
            List<UserRole> list = userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userProfile.getId()));
            if (!list.isEmpty()) {
                List<String> roles = roleService.list(
                        new LambdaQueryWrapper<Role>()
                                .in(Role::getId, list.stream()
                                        .map(UserRole::getRoleId)
                                        .collect(Collectors.toList())
                                )
                )
                        .stream()
                        .map(Role::getRoleString)
                        .collect(Collectors.toList());
                if (!roles.isEmpty()) {
                    String[] roleStr = roles.toArray(new String[0]);
                    tokenMap.put("roles", ArrayUtil.join(roleStr, ","));
                    String token = JwtUtil.generateToken(tokenMap);
                    HashMap<String, String> map = new HashMap<>();
                    map.put("token", token);
                    log.info("用户id:{},用户名:{}登陆系统", userProfile.getId(), userProfile.getUsername());
                    return ApiResponse.ofSuccess(map);
                }
            }
            return ApiResponse.ofStatus(Status.ACCESS_DENIED);
        }
        return ApiResponse.of(Status.ERROR.getCode(), "账号或密码错误", null);
    }

    /**
     * 检查用户修改密码的 key
     *
     * @param key 修改密码的 key
     * @return 返回是否修改成功
     */
    @Override
    public ApiResponse checkChangePwdKey(String key) {
        String userId = redisTemplate.opsForValue().get(key);
        return StrUtil.isNotEmpty(userId) ? ApiResponse.ofSuccess() : ApiResponse.of(Status.BAD_REQUEST.getCode(), "key失效了", null);
    }

}
